package jcataloger.gui;

import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Toolkit;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ActionMap;
import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.DefaultListModel;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.InputMap;
import javax.swing.JButton;
import javax.swing.JComponent;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JSplitPane;
import javax.swing.KeyStroke;
import javax.swing.ListSelectionModel;
import javax.swing.ProgressMonitor;
import javax.swing.SwingUtilities;

import jcataloger.beans.DiskImageInfo;
import jcataloger.beans.ImageItem;
import jcataloger.data.DiskImage;
import jcataloger.data.JRCFileFilter;
import jcataloger.renderers.JCatalogerListRenderer;
import jcataloger.resources.Messages;
import jcataloger.resources.Parameters;
import jcataloger.util.DirectoryTreeCreator;
import jcataloger.util.Indexer;
import jcataloger.util.Utils;
import jcataloger.util.ZipUtils;


/**
 * This is the executable class of the project.
 * @author sekobey
 *
 */
@SuppressWarnings("serial")
public class MainFrame extends JFrame implements JCatalogerParams {
	private JButton buttonNew;
	private JButton buttonOpen;
	private JButton buttonSave;
	private JButton buttonAdd;
	private JButton buttonDelete;
	private JButton buttonSearch;
	private JSplitPane splitPane;
	private JLabel labelStatus;
	private JMenuBar menuBarFrame;
	private JMenu menuFile;
	private JMenu menuTools;
	private JMenu menuLanguage;
	private JMenu menuHelp;
	private JMenuItem menuItemNew;
	private JMenuItem menuItemOpen;
	private JMenuItem menuItemSave;
	private JMenuItem menuItemSaveAs;
	private JMenuItem menuItemExit;
	private JMenuItem menuItemAdd;
	private JMenuItem menuItemDelete;
	private JMenuItem menuItemSearch;
	private JMenuItem menuItemAbout;
	private JMenuItem menuItemHelp;
	private JPanel northPanel;
	private JPanel centerPanel;
	private JPanel southPanel;
	private JList listDirectory;
	private JList listImageNames;
	private Action actionNew;
	private Action actionOpen;
	private Action actionSave;
	private Action actionAdd;
	private Action actionDelete;
	private Action actionSearch;
	private List<DiskImageInfo> diskImageList;
	private Stack<Integer> directoryHist;
	private DiskImage diskImage;
	private File openedFile = null, tempFile = null;
	private Indexer indexer;

	/**
	 * default constructor
	 *
	 */
	public MainFrame() {
		super(Messages.getString("title.mainframe"));
		// this program requires Java 5 minimum
		int version = Integer.parseInt(""+System.getProperty("java.version").charAt(2));
		if ( version < 5 ) {
			JOptionPane.showMessageDialog(this, Messages.getString("MainFrame.79"), Messages.getString("title.error"), JOptionPane.ERROR_MESSAGE);
			throw new RuntimeException(Messages.getString("MainFrame.79"));
		}
		
		actionNew = new NewAction();
		actionAdd = new AddImageAction();
		actionSave = new SaveAction();
		actionOpen = new OpenAction();
		actionDelete = new DeleteAction();
		actionSearch = new SearchAction();
		diskImage = DiskImage.getInstance();
		diskImageList = new ArrayList<DiskImageInfo>();
		directoryHist = new Stack<Integer>();
		indexer = Indexer.openIndex();
		tempFile = new File(TEMP_FILE);
		tempFile.deleteOnExit();
		
		init();
		
	}

	private void init() {
		this.setSize( new Dimension(700, 500) );
		this.setPreferredSize( new Dimension(700, 500) );
		Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
		this.setLocation( (screenSize.width-this.getWidth())/2, 
				(screenSize.height-this.getHeight())/2 );

		JPanel northPanel = getNorthPanel();
		JPanel centerPanel = getCenterPanel();
		JPanel southPanel = getSouthPanel();

		initKeyMappings();
		
		Container c = getContentPane();
		c.add( northPanel, BorderLayout.NORTH );
		c.add( centerPanel, BorderLayout.CENTER );
		c.add( southPanel, BorderLayout.SOUTH );

		this.setJMenuBar( getMenuBarFrame() );

		this.addWindowListener(
				new WindowAdapter() {
					public void windowClosing(WindowEvent e) {
						exit();
					}
				}
		);
	}

	private void initKeyMappings() {
		InputMap imap = getCenterPanel().getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW);
		ActionMap amap = getCenterPanel().getActionMap();
		imap.put(KeyStroke.getKeyStroke(Parameters.getString("key.new")), "action.new");
		amap.put("action.new", actionNew);
		imap.put(KeyStroke.getKeyStroke(Parameters.getString("key.open")), "action.open");
		amap.put("action.open", actionOpen);
		imap.put(KeyStroke.getKeyStroke(Parameters.getString("key.save")), "action.save");
		amap.put("action.save", actionSave);
		imap.put(KeyStroke.getKeyStroke(Parameters.getString("key.add")), "action.add");
		amap.put("action.add", actionAdd);
		imap.put(KeyStroke.getKeyStroke(Parameters.getString("key.delete")), "action.delete");
		amap.put("action.delete", actionDelete);
		imap.put(KeyStroke.getKeyStroke(Parameters.getString("key.search")), "action.search");
		amap.put("action.search", actionSearch);
	}

	private JPanel getNorthPanel() {
		if (northPanel == null) {

			buttonNew = new JButton();
			buttonNew.setAction( actionNew );
			buttonOpen = new JButton();
			buttonOpen.setAction( actionOpen );
			buttonSave = new JButton();
			buttonSave.setAction( actionSave );
			buttonSave.setEnabled( false );
			buttonAdd = new JButton();
			buttonAdd.setAction( actionAdd );
			buttonDelete = new JButton();
			buttonDelete.setAction( actionDelete );
			buttonDelete.setEnabled( false );
			buttonSearch = new JButton();
			buttonSearch.setAction( actionSearch );
			buttonSearch.setEnabled(false);

			northPanel = new JPanel();
			FlowLayout f = new FlowLayout(FlowLayout.LEFT);
			northPanel.setLayout( f );

			northPanel.add(buttonNew);
			northPanel.add(buttonOpen);
			northPanel.add(buttonSave);
			northPanel.add(buttonAdd);
			northPanel.add(buttonDelete);
			northPanel.add(buttonSearch);
			
		}

		return northPanel;
	}

	private JPanel getCenterPanel() {
		if (centerPanel == null) {
			MouseHandler mouseHandler = new MouseHandler();

			listImageNames = new JList( new DefaultListModel() );
			listImageNames.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
			listImageNames.addMouseListener( mouseHandler );
			listImageNames.setCellRenderer( new JCatalogerListRenderer() );

			listDirectory = new JList( new DefaultListModel() );
			listDirectory.setSelectionMode( ListSelectionModel.SINGLE_SELECTION );
			listDirectory.addMouseListener( mouseHandler );
			listDirectory.setCellRenderer( new JCatalogerListRenderer() );

			JScrollPane imageScroller = new JScrollPane( listImageNames );
			JScrollPane directoryScroller = new JScrollPane( listDirectory );
			splitPane = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, imageScroller, directoryScroller);
			splitPane.setContinuousLayout( true );
			splitPane.setOneTouchExpandable( true );
			int loc = this.getWidth()/4;
			splitPane.setDividerLocation(loc);

			centerPanel = new JPanel();
			centerPanel.setLayout( new BorderLayout() );
			centerPanel.add( splitPane, BorderLayout.CENTER );
		}

		return centerPanel;
	}

	private JPanel getSouthPanel() {
		if (southPanel == null) {
			labelStatus = new JLabel(" ");
			labelStatus.setBorder( BorderFactory.createLoweredBevelBorder() );
			southPanel = new JPanel();
			southPanel.setLayout( new BorderLayout() );
			southPanel.add(labelStatus, BorderLayout.CENTER);
		}

		return southPanel;
	}

	private JMenuBar getMenuBarFrame() {
		if (menuBarFrame == null) {
			menuBarFrame = new JMenuBar();
			menuBarFrame.add( getFileMenu() );
			menuBarFrame.add( getToolsMenu() );
			menuBarFrame.add( getLanguageMenu() );
			menuBarFrame.add( getHelpMenu() );
		}

		return menuBarFrame;
	}

	private JMenu getFileMenu() {

		if (menuFile == null) {
			ClassLoader loader = this.getClass().getClassLoader();

			menuFile = new JMenu(Messages.getString("MainFrame.0"));
			menuFile.setMnemonic(menuFile.getText().charAt(0));

			menuItemNew = new JMenuItem(actionNew);
			menuItemNew.setText(Messages.getString("MainFrame.31")); //$NON-NLS-1$
			menuItemNew.setIcon(new ImageIcon(loader.getResource(Parameters.getString("icons22x22.filenew")))); //$NON-NLS-1$
			menuItemNew.setAccelerator(KeyStroke.getKeyStroke(Parameters.getString("key.new")));
			menuItemOpen = new JMenuItem(actionOpen);
			menuItemOpen.setText(Messages.getString("MainFrame.33")); //$NON-NLS-1$
			menuItemOpen.setIcon(new ImageIcon(loader.getResource(Parameters.getString("icons22x22.fileopen")))); //$NON-NLS-1$
			menuItemOpen.setAccelerator(KeyStroke.getKeyStroke(Parameters.getString("key.open")));
			menuItemSave = new JMenuItem(actionSave);
			menuItemSave.setText(Messages.getString("MainFrame.35")); //$NON-NLS-1$
			menuItemSave.setIcon(new ImageIcon(loader.getResource(Parameters.getString("icons22x22.filesave")))); //$NON-NLS-1$
			menuItemSave.setAccelerator(KeyStroke.getKeyStroke(Parameters.getString("key.save")));
			menuItemSave.setEnabled(false);
			menuItemSaveAs = new JMenuItem(Messages.getString("MainFrame.37"), new ImageIcon(loader.getResource(Parameters.getString("icons22x22.filesaveas")))); //$NON-NLS-1$ //$NON-NLS-2$
			menuItemSaveAs.setEnabled(false);
			menuItemSaveAs.addActionListener(
					new ActionListener() {
						public void actionPerformed(ActionEvent e) {

							JFileChooser chooser = new JFileChooser();
							JRCFileFilter filter = new JRCFileFilter("cat",Messages.getString("MainFrame.18"));
							chooser.addChoosableFileFilter( filter );
							int val = chooser.showSaveDialog( MainFrame.this );
							if ( val == JFileChooser.APPROVE_OPTION ) {
								File fileToSave = chooser.getSelectedFile();
								if ( fileToSave.exists() ) {
									int choice = JOptionPane.showConfirmDialog(MainFrame.this, Messages.getString("MainFrame.12"), Messages.getString("title.question"), JOptionPane.YES_NO_OPTION);
									if ( choice == JOptionPane.NO_OPTION )
										return;
								}
								// make every disk image default, so they are saved in index when exiting
								for (DiskImageInfo image : diskImageList) {
									image.setSaved(true);
								}

								diskImage.setImages( diskImageList );
								diskImage.write(tempFile);
								// compress the index and file
								zipToFile(fileToSave);
								// button configuration
								buttonSave.setEnabled( false );
								menuItemSave.setEnabled( false );
								// opened file must be saved file
								openedFile = fileToSave;
								labelStatus.setText(Messages.getString("MainFrame.19")); //$NON-NLS-1$
							}
						}
					}
			);
			menuItemExit = new JMenuItem(Messages.getString("MainFrame.42"), new ImageIcon(loader.getResource(Parameters.getString("icons22x22.fileclose")))); //$NON-NLS-1$ //$NON-NLS-2$
			menuItemExit.addActionListener(
					new ActionListener() {
						public void actionPerformed(ActionEvent e) {
							exit();
						}
					}
			);

			menuFile.add(menuItemNew);
			menuFile.insertSeparator(1);
			menuFile.add(menuItemOpen);
			menuFile.add(menuItemSave);
			menuFile.add(menuItemSaveAs);
			menuFile.insertSeparator(5);
			menuFile.add(menuItemExit);
		}
		return menuFile;
	}

	private JMenu getToolsMenu() {

		if ( menuTools == null ) {
			ClassLoader loader = this.getClass().getClassLoader();

			menuTools = new JMenu(Messages.getString("MainFrame.44"));
			menuTools.setMnemonic(menuTools.getText().charAt(0));

			menuItemAdd = new JMenuItem(actionAdd);
			menuItemAdd.setText(Messages.getString("MainFrame.45"));
			menuItemAdd.setIcon(new ImageIcon(loader.getResource(Parameters.getString("icons22x22.add")))); //$NON-NLS-1$
			menuItemAdd.setAccelerator(KeyStroke.getKeyStroke(Parameters.getString("key.add")));
			menuItemDelete = new JMenuItem(actionDelete);
			menuItemDelete.setText(Messages.getString("MainFrame.47"));
			menuItemDelete.setIcon(new ImageIcon(loader.getResource(Parameters.getString("icons22x22.remove")))); //$NON-NLS-1$
			menuItemDelete.setAccelerator(KeyStroke.getKeyStroke(Parameters.getString("key.delete")));
			menuItemDelete.setEnabled(false);
			menuItemSearch = new JMenuItem(actionSearch);
			menuItemSearch.setText(Messages.getString("MainFrame.49"));
			menuItemSearch.setIcon(new ImageIcon(loader.getResource(Parameters.getString("icons22x22.search")))); //$NON-NLS-1$
			menuItemSearch.setAccelerator(KeyStroke.getKeyStroke(Parameters.getString("key.search")));
			menuItemSearch.setEnabled(false);

			menuTools.add(menuItemAdd);
			menuTools.add(menuItemDelete);
			menuTools.add(menuItemSearch);
		}
		return menuTools;
	}

	private JMenu getLanguageMenu() {
		if (menuLanguage == null) {

			menuLanguage = new JMenu(Messages.getString("MainFrame.80"));
			menuLanguage.setMnemonic(menuLanguage.getText().charAt(0));

			JRadioButtonMenuItem itemTurkce = new JRadioButtonMenuItem("T\u00FCrk\u00E7e");
			itemTurkce.addActionListener(
					new ActionListener() {
						public void actionPerformed(ActionEvent e) {
							Messages.setLocale("tr", "TR");
							updateButtonTexts();
						}
					}
			);

			JRadioButtonMenuItem itemEnglish = new JRadioButtonMenuItem("English");
			itemEnglish.addActionListener(
					new ActionListener() {
						public void actionPerformed(ActionEvent e) {
							Messages.setLocale("en", "US");
							updateButtonTexts();
						}
					}
			);
			itemEnglish.setSelected(true);
			ButtonGroup group = new ButtonGroup();
			group.add(itemTurkce);
			group.add(itemEnglish);

			menuLanguage.add(itemTurkce);
			menuLanguage.add(itemEnglish);
		}

		return menuLanguage;
	}

	private JMenu getHelpMenu() {
		if ( menuHelp == null ) {
			menuHelp = new JMenu(Messages.getString("MainFrame.51")); //$NON-NLS-1$
			menuHelp.setMnemonic(menuHelp.getText().charAt(0));

			menuItemAbout = new JMenuItem(Messages.getString("MainFrame.52")); //$NON-NLS-1$
			menuItemAbout.addActionListener(
					new ActionListener() {
						public void actionPerformed(ActionEvent e) {
							AboutFrame aboutGUI = new AboutFrame(MainFrame.this);
							aboutGUI.setVisible(true);
						}
					}
			);
			menuItemHelp = new JMenuItem(Messages.getString("MainFrame.53"));
			menuItemHelp.addActionListener(
					new ActionListener() {
						public void actionPerformed(ActionEvent e) {
							HelpFrame help = new HelpFrame(MainFrame.this);
							help.setVisible(true);
						}
					}
			);
			menuItemHelp.setAccelerator(KeyStroke.getKeyStroke(Parameters.getString("key.help")));
			
			menuHelp.add(menuItemHelp);
			menuHelp.add(menuItemAbout);
			

		}

		return menuHelp; 
	}

	/**
	 * This action is used for creating a new catalog. It is commonly used between GUI elements.
	 * @author sekobey
	 *
	 */
	@SuppressWarnings("serial")
	class NewAction extends AbstractAction {
		@SuppressWarnings("unused")
		private SearchFrame searchGui;
		public NewAction() {
			ClassLoader loader = this.getClass().getClassLoader();
			Icon newIcon = new ImageIcon(loader.getResource(Parameters.getString("icons32x32.filenew"))); //$NON-NLS-1$
			searchGui = new SearchFrame( MainFrame.this );
			putValue(Action.SHORT_DESCRIPTION, Messages.getString("MainFrame.2")); //$NON-NLS-1$
			putValue(Action.SMALL_ICON, newIcon);
		}

		public void actionPerformed(ActionEvent e) {
			int result = -7;
			if ( diskImage.isDirty() ) {
				save(true);
			}
			if ( result != JOptionPane.CANCEL_OPTION ) {	
				while ( diskImageList.size() > 0 ) {
					diskImageList.remove(0);
				}
				diskImage.setImages( null );
				DefaultListModel treeModel = (DefaultListModel)listImageNames.getModel();
				treeModel.removeAllElements();
				DefaultListModel listModel = (DefaultListModel)listDirectory.getModel();
				listModel.removeAllElements();

				// remove images from index
				indexer.deleteAllDiskImages();
				
				openedFile = null;

				// button configuration
				buttonSave.setEnabled( false );
				buttonSearch.setEnabled( false );
				buttonDelete.setEnabled( false );
				menuItemSave.setEnabled( false );
				menuItemSaveAs.setEnabled( false );
				menuItemSearch.setEnabled( false );
				menuItemDelete.setEnabled( false );

				// set status
				labelStatus.setText(Messages.getString("MainFrame.3")); //$NON-NLS-1$
			}
		}
	}

	/**
	 * This action is used for adding a disk image to a catalog. It is commonly used between GUI elements.
	 * @author sekobey
	 *
	 */
	@SuppressWarnings("serial")
	class AddImageAction extends AbstractAction {

		public AddImageAction() {
			ClassLoader loader = this.getClass().getClassLoader();
			Icon addIcon = new ImageIcon(loader.getResource(Parameters.getString("icons32x32.add"))); //$NON-NLS-1$
			putValue( Action.SHORT_DESCRIPTION, Messages.getString("MainFrame.5")); //$NON-NLS-1$
			putValue( Action.SMALL_ICON, addIcon );
		}

		public void actionPerformed(ActionEvent e) {

			Thread t = new Thread() {
				public void run() {

					// Selecting Root
					RootSelectionDialog selectionGui = new RootSelectionDialog(MainFrame.this);
					selectionGui.setVisible(true);
					File root = selectionGui.getSelection();
					selectionGui.setVisible(false);
					if ( selectionGui.isCancelled() )
						return;

					// progress monitor is constructed to show the adding progress
					ProgressMonitor monitor = new ProgressMonitor(MainFrame.this, Messages.getString("MainFrame.58"), Messages.getString("MainFrame.59"), 0, 50000); //$NON-NLS-1$ //$NON-NLS-2$
					monitor.setMillisToDecideToPopup(0);
					monitor.setMillisToPopup(0);
					Map<Integer, List<ImageItem>> directoryMap = getDirectoryMap(root.getPath(), monitor);
					if ( directoryMap != null ) {
						String diskName = JOptionPane.showInputDialog( MainFrame.this, Messages.getString("MainFrame.7")); //$NON-NLS-1$
						while ( true ) {
							// if the cancel is chosen in input dialog, return
							if ( diskName == null) {
								monitor.close();
								return;
							}
							if ( Utils.isDiskExist( diskName, diskImageList ) )
								diskName = JOptionPane.showInputDialog( MainFrame.this, Messages.getString("MainFrame.8"), diskName); //$NON-NLS-1$
							else
								break;
						}
						// add image to index
						monitor.setNote(Messages.getString("MainFrame.60")); //$NON-NLS-1$
						indexer.addDiskImage(diskName, directoryMap);
						monitor.setProgress(47000);

						monitor.setNote(Messages.getString("MainFrame.61")); //$NON-NLS-1$
						// adding image name to image tree
						DefaultListModel treeModel = (DefaultListModel)listImageNames.getModel();
						treeModel.addElement( diskName );
						listImageNames.setSelectedIndex( listImageNames.getLastVisibleIndex() );

						// adding image to list
						monitor.setProgress(49000);
						DefaultListModel listModel = (DefaultListModel)listDirectory.getModel();
						listModel.removeAllElements();
						List<ImageItem> directoryList = directoryMap.get(0);
						for ( ImageItem item : directoryList) {
							listModel.addElement( item );
						}

						// setting necessary fields
						diskImageList.add( new DiskImageInfo( diskName, directoryMap, false ) );
						diskImage.setDirty( true );

						// button configuration
						buttonSave.setEnabled(true);
						buttonSearch.setEnabled( true );
						buttonDelete.setEnabled( true );
						menuItemSave.setEnabled( true );
						menuItemSaveAs.setEnabled( true );
						menuItemSearch.setEnabled( true );
						menuItemDelete.setEnabled( true );

						labelStatus.setText(Messages.getString("MainFrame.9")); //$NON-NLS-1$
						monitor.setProgress(50000);
						monitor.close();
					}
					else {
						labelStatus.setText(Messages.getString("MainFrame.10")); //$NON-NLS-1$
					}

				}
			}; t.start();

		}

		private Map<Integer, List<ImageItem>> getDirectoryMap(String path, ProgressMonitor monitor) {
			Map<Integer, List<ImageItem>> directoryMap = null;
			DirectoryTreeCreator creator = null;
			creator = new DirectoryTreeCreator( path, 0, 40000 );
			creator.start();
			int progress = 0;
			while ( true ) {
				progress = creator.getProgress();
				monitor.setProgress( progress );
				if ( monitor.isCanceled() ) {
					creator.stop();
					directoryMap = null;
					break;
				}
				if ( progress == creator.getMax() ) {
					directoryMap = creator.getDirectoryMap();
					break;
				}
			}
			return directoryMap;
		}
	}

	/**
	 * This action is used for saving a catalog. It is commonly used between GUI elements.
	 * @author sekobey
	 *
	 */
	@SuppressWarnings("serial") //$NON-NLS-1$
	class SaveAction extends AbstractAction {

		public SaveAction() {
			ClassLoader loader = this.getClass().getClassLoader();
			Icon saveIcon = new ImageIcon(loader.getResource(Parameters.getString("icons32x32.filesave")));  //$NON-NLS-1$
			putValue(Action.SHORT_DESCRIPTION, Messages.getString("MainFrame.14"));  //$NON-NLS-1$
			putValue( Action.SMALL_ICON, saveIcon );
		}

		public void actionPerformed(ActionEvent e) {
			// progress monitor is constructed to show the saving progress
			ProgressMonitor monitor = new ProgressMonitor(MainFrame.this, Messages.getString("MainFrame.67"), Messages.getString("MainFrame.68"), 0, 100); //$NON-NLS-1$ //$NON-NLS-2$
			save(false);
			monitor.setProgress(100);
			monitor.close();
		}
	}

	private void save(boolean showDialog) {
		if ( diskImage.isDirty() ) {

			if ( showDialog ) {
				int choice = JOptionPane.showConfirmDialog( this, Messages.getString("MainFrame.15"), Messages.getString("title.question"), JOptionPane.YES_NO_OPTION); //$NON-NLS-1$ //$NON-NLS-2$
				if ( choice == JOptionPane.NO_OPTION )
					return;
			}

			File fileToSave = null;
			if ( openedFile != null ) {
				fileToSave = openedFile;
			}
			else {
				JFileChooser chooser = new JFileChooser();
				JRCFileFilter filter = new JRCFileFilter("cat",Messages.getString("MainFrame.18")); //$NON-NLS-1$ //$NON-NLS-2$
				chooser.setFileFilter( filter );
				chooser.setAcceptAllFileFilterUsed(false);
				int val = chooser.showSaveDialog( this );
				if ( val == JFileChooser.APPROVE_OPTION ) {
					fileToSave = chooser.getSelectedFile();
					if ( fileToSave.exists() ) {
						int choice = JOptionPane.showConfirmDialog(this, Messages.getString("MainFrame.12"), Messages.getString("title.question"), JOptionPane.YES_NO_OPTION);
						if ( choice == JOptionPane.NO_OPTION )
							return;
					}
					fileToSave = Utils.createExtension(fileToSave);
				}
				else if ( val == JFileChooser.CANCEL_OPTION ) {
					return;
				}
			}
			if ( fileToSave != null ) {

				// make every disk image default
				for (DiskImageInfo image : diskImageList) {
					image.setSaved(true);
				}

				diskImage.setImages( diskImageList );
				diskImage.write(tempFile);
				zipToFile(fileToSave);
				buttonSave.setEnabled( false );
				menuItemSave.setEnabled( false );
				labelStatus.setText(Messages.getString("MainFrame.19")); //$NON-NLS-1$
			}
		}
	}

	/**
	 * This action is used for opening an existing catalog. It is commonly used between GUI elements.
	 * @author sekobey
	 *
	 */
	class OpenAction extends AbstractAction {

		public OpenAction() {
			ClassLoader loader = this.getClass().getClassLoader();
			Icon openIcon = new ImageIcon(loader.getResource(Parameters.getString("icons32x32.fileopen"))); //$NON-NLS-1$
			putValue(Action.SHORT_DESCRIPTION, Messages.getString("MainFrame.21")); //$NON-NLS-1$
			putValue( Action.SMALL_ICON, openIcon );
		}

		public void actionPerformed(ActionEvent e) {
			if ( diskImage.isDirty() ) {
				save(true);
			}

			final JFileChooser chooser = new JFileChooser();
			JRCFileFilter filter = new JRCFileFilter("cat",Messages.getString("MainFrame.18")); //$NON-NLS-1$ //$NON-NLS-2$
			chooser.setFileFilter( filter );
			chooser.setAcceptAllFileFilterUsed(false);
			int val = chooser.showOpenDialog( MainFrame.this );
			if ( val == JFileChooser.APPROVE_OPTION ) {

				Thread t = new Thread() {
					public void run() {
						labelStatus.setText(Messages.getString("MainFrame.24")); //$NON-NLS-1$
						// progress monitor is constructed to show the opening progress
						ProgressMonitor monitor = new ProgressMonitor(MainFrame.this, Messages.getString("MainFrame.73"), Messages.getString("MainFrame.74"), 0, 100); //$NON-NLS-1$ //$NON-NLS-2$
						openedFile = chooser.getSelectedFile();
						// unzipping archive
						ZipUtils.unzip(openedFile);
						// merge with index
						indexer.merge();
						// reading file
						diskImage.read(TEMP_FILE);
						monitor.setProgress(50);
						// getting all images
						diskImageList = diskImage.getImages();
						
						monitor.setNote(Messages.getString("MainFrame.75"));
						DefaultListModel modelImageName = (DefaultListModel)listImageNames.getModel();
						modelImageName.removeAllElements();
						DefaultListModel modelDirectory = (DefaultListModel)listDirectory.getModel();
						modelDirectory.removeAllElements();
						if ( diskImageList.size() > 0 ) {
							// configuring image name list
							for ( DiskImageInfo info : diskImageList ) {
								modelImageName.addElement( info.getDiskName() );
							}
							listImageNames.setSelectedIndex( 0 );
							// configuring directory list
							monitor.setProgress(75);
							DiskImageInfo info = Utils.findDiskImage( listImageNames.getSelectedValue().toString(), diskImageList );
							List<ImageItem> list = info.getDirectoryList().get(0);
							for ( ImageItem item : list) {
								modelDirectory.addElement( item );
							}
							monitor.setProgress(100);
							// button configuration
							buttonSave.setEnabled( false );
							buttonDelete.setEnabled( true );
							buttonSearch.setEnabled( true );
							menuItemSave.setEnabled( false );
							menuItemSaveAs.setEnabled( true );
							menuItemSearch.setEnabled( true );
							menuItemDelete.setEnabled( true );
						}
						else {
							// button configuration
							buttonSave.setEnabled( false );
							buttonDelete.setEnabled( false );
							buttonSearch.setEnabled( false );
							menuItemSave.setEnabled( false );
							menuItemSaveAs.setEnabled( true );
							menuItemSearch.setEnabled( false );
							menuItemDelete.setEnabled( false );
						}
						labelStatus.setText(Messages.getString("MainFrame.25")); //$NON-NLS-1$
						monitor.close();
					}
				};t.start();

			}

		}

	}

	/**
	 * This action is used for removing an image from the catalog. It is commonly used between GUI elements.
	 * @author sekobey
	 *
	 */
	class DeleteAction extends AbstractAction {
		private static final long serialVersionUID = -8010991014674419749L;

		public DeleteAction() {
			ClassLoader loader = this.getClass().getClassLoader();
			Icon deleteIcon = new ImageIcon(loader.getResource(Parameters.getString("icons32x32.remove"))); //$NON-NLS-1$
			putValue(Action.SHORT_DESCRIPTION, Messages.getString("MainFrame.27")); //$NON-NLS-1$
			putValue( Action.SMALL_ICON, deleteIcon );
		}

		public void actionPerformed(ActionEvent e) {
			if ( diskImageList.size() > 0 ) {
				// progress monitor is constructed to show the saving progress
				ProgressMonitor monitor = new ProgressMonitor(MainFrame.this, Messages.getString("MainFrame.76"), Messages.getString("MainFrame.61"), 0, 100); //$NON-NLS-1$ //$NON-NLS-2$
				String imageName = listImageNames.getSelectedValue().toString();
				DefaultListModel treeModel = (DefaultListModel)listImageNames.getModel();
				treeModel.remove( listImageNames.getSelectedIndex() );
				Utils.removeDiskImageFromList( imageName, diskImageList );
				// delete image from index
				monitor.setProgress(50);
				monitor.setNote(Messages.getString("MainFrame.78")); //$NON-NLS-1$
				int numOfDeletedItems = indexer.deleteDiskImage(imageName);
				DefaultListModel listModel = (DefaultListModel)listDirectory.getModel();
				listModel.removeAllElements();
				if ( listImageNames.getModel().getSize() > 0 ) {
					listImageNames.setSelectedIndex(0);
					DiskImageInfo info = Utils.findDiskImage( listImageNames.getSelectedValue().toString(), diskImageList );
					List<ImageItem> list = info.getDirectoryList().get(null);
					for ( ImageItem item : list) {
						listModel.addElement( item );
					}
				}
				else {
					buttonDelete.setEnabled( false );
					menuItemDelete.setEnabled( false );
					buttonSearch.setEnabled( false );
					menuItemSearch.setEnabled( false );
				}

				// button configuration
				diskImage.setDirty( true );
				buttonSave.setEnabled( true );
				menuItemSave.setEnabled( true );
				menuItemSaveAs.setEnabled( true );

				labelStatus.setText(Messages.getString("MainFrame.28", ""+numOfDeletedItems)); //$NON-NLS-1$
				monitor.setProgress(100);
				monitor.close();
			}
		}
	}

	/**
	 * This action is used for searching the catalog. It is commonly used between GUI elements.
	 * @author sekobey
	 *
	 */
	@SuppressWarnings("serial") //$NON-NLS-1$
	class SearchAction extends AbstractAction {

		private SearchFrame searchGui;
		public SearchAction() {
			ClassLoader loader = this.getClass().getClassLoader();
			searchGui = new SearchFrame( MainFrame.this );
			Icon searchIcon = new ImageIcon(loader.getResource(Parameters.getString("icons32x32.search"))); //$NON-NLS-1$
			putValue(Action.SHORT_DESCRIPTION, Messages.getString("MainFrame.30")); //$NON-NLS-1$
			putValue( Action.SMALL_ICON, searchIcon );
		}

		public void actionPerformed(ActionEvent e) {
			searchGui.clearForm();
			searchGui.setVisible( true );
			searchGui.requestFocus();
		}
	}

	/**
	 * Handles mouse events
	 * @author sekobey
	 *
	 */
	class MouseHandler extends MouseAdapter {
		public void mouseClicked( MouseEvent e ) {

			if ( e.getSource() == listImageNames && diskImageList.size() > 0) {
				String val = (String)listImageNames.getSelectedValue();
				DiskImageInfo info = Utils.findDiskImage( val, diskImageList );
				List<ImageItem> list = info.getDirectoryList().get(null);
				DefaultListModel listModel = (DefaultListModel)listDirectory.getModel();
				listModel.removeAllElements();
				for ( ImageItem item : list) {
					listModel.addElement( item );
				}
			}
			if ( e.getSource() == listDirectory && diskImageList.size() > 0 ) {
				if ( e.getClickCount() == 2 ) {
					String imageName = (String)listImageNames.getSelectedValue();
					ImageItem directory = (ImageItem)listDirectory.getSelectedValue();
					DiskImageInfo info = Utils.findDiskImage( imageName, diskImageList );
					if ( directory.isUpDirectory() ) {
						Integer parentHash = directoryHist.pop();
						List<ImageItem>	list = info.getDirectoryList().get( parentHash );
						DefaultListModel listModel = (DefaultListModel)listDirectory.getModel();
						listModel.removeAllElements();
						if ( parentHash != null )
							listModel.addElement( new ImageItem(new File(".."), null) ); //$NON-NLS-1$
						for ( ImageItem item : list) {
							listModel.addElement( item );
						}
					}
					else {
						List<ImageItem> list = info.getDirectoryList().get( directory.getFileHash() );
						if ( list != null ) {
							directoryHist.push( directory.getParentHash() );
							DefaultListModel listModel = (DefaultListModel)listDirectory.getModel();
							listModel.removeAllElements();
							listModel.addElement( new ImageItem(new File(".."), null) ); //$NON-NLS-1$
							for ( ImageItem item : list) {
								listModel.addElement( item );
							}
						}
					}
				}
			}
		}
	}

	private void exit() {
		// delete not saved images from index
		for (DiskImageInfo image : diskImageList) {
			if ( !image.isSaved() )
				indexer.deleteDiskImage(image.getDiskName());
		}
		indexer.closeIndex();

		// ask to save if disk image is changed
		if ( diskImage.isDirty() ) {
			save(true);
		}

		System.exit(0);
	}

	private void updateButtonTexts() {
		buttonNew.setToolTipText(Messages.getString("MainFrame.2"));
		buttonOpen.setToolTipText(Messages.getString("MainFrame.21"));
		buttonSave.setToolTipText(Messages.getString("MainFrame.14"));
		buttonAdd.setToolTipText(Messages.getString("MainFrame.5"));
		buttonDelete.setToolTipText(Messages.getString("MainFrame.27"));
		buttonSearch.setToolTipText(Messages.getString("MainFrame.30"));
		menuFile.setText(Messages.getString("MainFrame.0"));
		menuFile.setMnemonic(menuFile.getText().charAt(0));
		menuTools.setText(Messages.getString("MainFrame.44"));
		menuTools.setMnemonic(menuTools.getText().charAt(0));
		menuLanguage.setText(Messages.getString("MainFrame.80"));
		menuLanguage.setMnemonic(menuLanguage.getText().charAt(0));
		menuHelp.setText(Messages.getString("MainFrame.51"));
		menuHelp.setMnemonic(menuHelp.getText().charAt(0));
		menuItemNew.setText(Messages.getString("MainFrame.31"));
		menuItemNew.setToolTipText(Messages.getString("MainFrame.2"));
		menuItemOpen.setText(Messages.getString("MainFrame.33"));
		menuItemOpen.setToolTipText(Messages.getString("MainFrame.21"));
		menuItemSave.setText(Messages.getString("MainFrame.35"));
		menuItemSave.setToolTipText(Messages.getString("MainFrame.14"));
		menuItemSaveAs.setText(Messages.getString("MainFrame.37"));
		menuItemExit.setText(Messages.getString("MainFrame.42")); 
		menuItemAdd.setText(Messages.getString("MainFrame.45"));
		menuItemAdd.setToolTipText(Messages.getString("MainFrame.5"));
		menuItemDelete.setText(Messages.getString("MainFrame.47"));
		menuItemDelete.setToolTipText(Messages.getString("MainFrame.27"));
		menuItemSearch.setText(Messages.getString("MainFrame.49"));
		menuItemSearch.setToolTipText(Messages.getString("MainFrame.30"));
		menuItemAbout.setText(Messages.getString("MainFrame.52"));
		menuItemHelp.setText(Messages.getString("MainFrame.53"));

	}

	private void zipToFile(File fileToSave) {
		ZipUtils zipper = new ZipUtils();
		zipper.add(tempFile);
		zipper.add(new File(INDEX_DIR));
		zipper.zipToFile(fileToSave);
	}
	
	/**
	 * 
	 * @return disk images in a list in type DiskImageInfo.@see DiskImageInfo
	 */
	public List<DiskImageInfo> getDiskImageList() {
		return diskImageList;
	}

	public static void main(String[] args) {
		SwingUtilities.invokeLater(new Runnable() {
			public void run() {
				MainFrame main = new MainFrame();
				main.setVisible(true);
			}
		});
	}

}